package service

import (
	"context"
	"errors"
	"fmt"
	"gino/app/common"
	"gino/app/dao"
	"gino/app/model"
	"gino/global"
	"gino/pkg/glog"
	utils2 "gino/pkg/utils"
	"github.com/dgrijalva/jwt-go"
	"golang.org/x/crypto/bcrypt"
	"time"
)

var User = userService{} // 中间件管理服务

type userService struct{}

func (s *userService) Register(ctx context.Context, req model.UserRegisterReq) error {

	// 账号唯一性数据检查
	if !s.CheckUniqueUsername(ctx, req.Username) {
		return errors.New(fmt.Sprintf("账号 %s 已经存在", req.Username))
	}

	user := model.User{
		Username: req.Username,
		Password: utils2.BcryptHash(req.Password),
		State:    model.UserStateNormal,
	}

	if _, err := dao.User.Create(ctx, global.DB, user); err != nil {
		glog.Errorf("[service/user]Register dao.User.Create Err：%v", err)
		return err
	}

	return nil
}

func (s *userService) Login(ctx context.Context, req model.UserLoginReq) (ret model.UserLoginResp, err error) {

	// 查询用户信息
	user, err := dao.User.GetByUsername(ctx, global.DB, req.Username)
	if err != nil {
		return model.UserLoginResp{}, err
	}

	if ok := utils2.BcryptCheck(req.Password, user.Password); !ok {
		return model.UserLoginResp{}, errors.New("密码错误~")
	}

	if user.State != model.UserStateNormal {
		return model.UserLoginResp{}, errors.New("用户账号非正常状态~")
	}

	// 生成token CustomClaims
	j := utils2.NewJWT(global.Config.JWT.SignKey)
	token, err := j.CreateToken(utils2.CustomClaims{
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Unix() + global.Config.JWT.ExpireTime,
			Issuer:    global.Config.JWT.Issuer,
		},
	})

	return model.UserLoginResp{ID: user.ID, Username: user.Username, Token: token}, nil
}

func (s *userService) List(ctx context.Context, req model.UserListReq) (ret *common.PageResult, err error) {

	list, total, err := dao.User.List(ctx, global.DB, req)
	if err != nil {
		return nil, err
	}

	return common.NewPageResult(list, total, req.PageInfo), nil
}

// CheckUniqueUsername 检查账号是否符合规范(目前仅检查唯一性),存在返回false,否则true
func (s *userService) CheckUniqueUsername(ctx context.Context, username string) bool {

	count, err := dao.User.GetCountByUsername(ctx, global.DB, username)
	if err != nil {
		return false
	}

	return count == 0
}

// encryptedPassword 加密密码
func (s *userService) encryptedPassword(password string) (hashedPassword string, err error) {

	byTes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil { // 加密密码
		return "", err
	}

	return string(byTes), nil
}

// compareHashAndPassword 密码检查 false 校验失败, true 校验成功
func (s *userService) compareHashAndPassword(hashedPassword string, password string) bool {
	if err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)); err != nil {
		return false
	}
	return true
}
